; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=x86_64-unknown-unknown -O0 < %s | FileCheck --check-prefixes=CHECK,CHECK-O0 %s
; RUN: llc -mtriple=x86_64-unknown-unknown -O3 < %s | FileCheck --check-prefixes=CHECK,CHECK-O3 %s

declare void @external()
declare void @no_csr() "no_callee_saved_registers"

define void @normal() {
; CHECK-LABEL: normal:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pushq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    callq external@PLT
; CHECK-NEXT:    popq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 8
; CHECK-NEXT:    retq
  call void @external()
  ret void
}

; Calling a routine with no CSRs means the caller has to spill a bunch
define void @test1() {
; CHECK-LABEL: test1:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pushq %rbp
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    pushq %r15
; CHECK-NEXT:    .cfi_def_cfa_offset 24
; CHECK-NEXT:    pushq %r14
; CHECK-NEXT:    .cfi_def_cfa_offset 32
; CHECK-NEXT:    pushq %r13
; CHECK-NEXT:    .cfi_def_cfa_offset 40
; CHECK-NEXT:    pushq %r12
; CHECK-NEXT:    .cfi_def_cfa_offset 48
; CHECK-NEXT:    pushq %rbx
; CHECK-NEXT:    .cfi_def_cfa_offset 56
; CHECK-NEXT:    pushq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 64
; CHECK-NEXT:    .cfi_offset %rbx, -56
; CHECK-NEXT:    .cfi_offset %r12, -48
; CHECK-NEXT:    .cfi_offset %r13, -40
; CHECK-NEXT:    .cfi_offset %r14, -32
; CHECK-NEXT:    .cfi_offset %r15, -24
; CHECK-NEXT:    .cfi_offset %rbp, -16
; CHECK-NEXT:    callq external@PLT
; CHECK-NEXT:    addq $8, %rsp
; CHECK-NEXT:    .cfi_def_cfa_offset 56
; CHECK-NEXT:    popq %rbx
; CHECK-NEXT:    .cfi_def_cfa_offset 48
; CHECK-NEXT:    popq %r12
; CHECK-NEXT:    .cfi_def_cfa_offset 40
; CHECK-NEXT:    popq %r13
; CHECK-NEXT:    .cfi_def_cfa_offset 32
; CHECK-NEXT:    popq %r14
; CHECK-NEXT:    .cfi_def_cfa_offset 24
; CHECK-NEXT:    popq %r15
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    popq %rbp
; CHECK-NEXT:    .cfi_def_cfa_offset 8
; CHECK-NEXT:    retq
  call void @external() "no_callee_saved_registers"
  ret void
}

; Same as test1, but on callee, not callsite
define void @test2() {
; CHECK-LABEL: test2:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pushq %rbp
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    pushq %r15
; CHECK-NEXT:    .cfi_def_cfa_offset 24
; CHECK-NEXT:    pushq %r14
; CHECK-NEXT:    .cfi_def_cfa_offset 32
; CHECK-NEXT:    pushq %r13
; CHECK-NEXT:    .cfi_def_cfa_offset 40
; CHECK-NEXT:    pushq %r12
; CHECK-NEXT:    .cfi_def_cfa_offset 48
; CHECK-NEXT:    pushq %rbx
; CHECK-NEXT:    .cfi_def_cfa_offset 56
; CHECK-NEXT:    pushq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 64
; CHECK-NEXT:    .cfi_offset %rbx, -56
; CHECK-NEXT:    .cfi_offset %r12, -48
; CHECK-NEXT:    .cfi_offset %r13, -40
; CHECK-NEXT:    .cfi_offset %r14, -32
; CHECK-NEXT:    .cfi_offset %r15, -24
; CHECK-NEXT:    .cfi_offset %rbp, -16
; CHECK-NEXT:    callq no_csr@PLT
; CHECK-NEXT:    addq $8, %rsp
; CHECK-NEXT:    .cfi_def_cfa_offset 56
; CHECK-NEXT:    popq %rbx
; CHECK-NEXT:    .cfi_def_cfa_offset 48
; CHECK-NEXT:    popq %r12
; CHECK-NEXT:    .cfi_def_cfa_offset 40
; CHECK-NEXT:    popq %r13
; CHECK-NEXT:    .cfi_def_cfa_offset 32
; CHECK-NEXT:    popq %r14
; CHECK-NEXT:    .cfi_def_cfa_offset 24
; CHECK-NEXT:    popq %r15
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    popq %rbp
; CHECK-NEXT:    .cfi_def_cfa_offset 8
; CHECK-NEXT:    retq
  call void @no_csr()
  ret void
}

; on an invoke instead
define i32 @test3() personality i8* undef {
; CHECK-O0-LABEL: test3:
; CHECK-O0:       # %bb.0: # %entry
; CHECK-O0-NEXT:    pushq %rbp
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 16
; CHECK-O0-NEXT:    pushq %r15
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 24
; CHECK-O0-NEXT:    pushq %r14
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 32
; CHECK-O0-NEXT:    pushq %r13
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 40
; CHECK-O0-NEXT:    pushq %r12
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 48
; CHECK-O0-NEXT:    pushq %rbx
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 56
; CHECK-O0-NEXT:    pushq %rax
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 64
; CHECK-O0-NEXT:    .cfi_offset %rbx, -56
; CHECK-O0-NEXT:    .cfi_offset %r12, -48
; CHECK-O0-NEXT:    .cfi_offset %r13, -40
; CHECK-O0-NEXT:    .cfi_offset %r14, -32
; CHECK-O0-NEXT:    .cfi_offset %r15, -24
; CHECK-O0-NEXT:    .cfi_offset %rbp, -16
; CHECK-O0-NEXT:  .Ltmp0:
; CHECK-O0-NEXT:    callq no_csr@PLT
; CHECK-O0-NEXT:  .Ltmp1:
; CHECK-O0-NEXT:    jmp .LBB3_1
; CHECK-O0-NEXT:  .LBB3_1: # %invoke.cont
; CHECK-O0-NEXT:    movl $1, %eax
; CHECK-O0-NEXT:    addq $8, %rsp
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 56
; CHECK-O0-NEXT:    popq %rbx
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 48
; CHECK-O0-NEXT:    popq %r12
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 40
; CHECK-O0-NEXT:    popq %r13
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 32
; CHECK-O0-NEXT:    popq %r14
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 24
; CHECK-O0-NEXT:    popq %r15
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 16
; CHECK-O0-NEXT:    popq %rbp
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 8
; CHECK-O0-NEXT:    retq
; CHECK-O0-NEXT:  .LBB3_2: # %lpad
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 64
; CHECK-O0-NEXT:  .Ltmp2:
; CHECK-O0-NEXT:    xorl %eax, %eax
; CHECK-O0-NEXT:    addq $8, %rsp
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 56
; CHECK-O0-NEXT:    popq %rbx
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 48
; CHECK-O0-NEXT:    popq %r12
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 40
; CHECK-O0-NEXT:    popq %r13
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 32
; CHECK-O0-NEXT:    popq %r14
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 24
; CHECK-O0-NEXT:    popq %r15
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 16
; CHECK-O0-NEXT:    popq %rbp
; CHECK-O0-NEXT:    .cfi_def_cfa_offset 8
; CHECK-O0-NEXT:    retq
;
; CHECK-O3-LABEL: test3:
; CHECK-O3:       # %bb.0: # %entry
; CHECK-O3-NEXT:    pushq %rbp
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 16
; CHECK-O3-NEXT:    pushq %r15
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 24
; CHECK-O3-NEXT:    pushq %r14
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 32
; CHECK-O3-NEXT:    pushq %r13
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 40
; CHECK-O3-NEXT:    pushq %r12
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 48
; CHECK-O3-NEXT:    pushq %rbx
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 56
; CHECK-O3-NEXT:    pushq %rax
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 64
; CHECK-O3-NEXT:    .cfi_offset %rbx, -56
; CHECK-O3-NEXT:    .cfi_offset %r12, -48
; CHECK-O3-NEXT:    .cfi_offset %r13, -40
; CHECK-O3-NEXT:    .cfi_offset %r14, -32
; CHECK-O3-NEXT:    .cfi_offset %r15, -24
; CHECK-O3-NEXT:    .cfi_offset %rbp, -16
; CHECK-O3-NEXT:  .Ltmp0:
; CHECK-O3-NEXT:    callq no_csr@PLT
; CHECK-O3-NEXT:  .Ltmp1:
; CHECK-O3-NEXT:  # %bb.1: # %invoke.cont
; CHECK-O3-NEXT:    movl $1, %eax
; CHECK-O3-NEXT:  .LBB3_2: # %invoke.cont
; CHECK-O3-NEXT:    addq $8, %rsp
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 56
; CHECK-O3-NEXT:    popq %rbx
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 48
; CHECK-O3-NEXT:    popq %r12
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 40
; CHECK-O3-NEXT:    popq %r13
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 32
; CHECK-O3-NEXT:    popq %r14
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 24
; CHECK-O3-NEXT:    popq %r15
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 16
; CHECK-O3-NEXT:    popq %rbp
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 8
; CHECK-O3-NEXT:    retq
; CHECK-O3-NEXT:  .LBB3_3: # %lpad
; CHECK-O3-NEXT:    .cfi_def_cfa_offset 64
; CHECK-O3-NEXT:  .Ltmp2:
; CHECK-O3-NEXT:    xorl %eax, %eax
; CHECK-O3-NEXT:    jmp .LBB3_2
entry:
  invoke void @no_csr()
     to label %invoke.cont unwind label %lpad

invoke.cont:
  ret i32 1

lpad:
  %0 = landingpad { i8*, i32 }
          cleanup
  ret i32 0
}

define void @no_csr_func() "no_callee_saved_registers" {
; CHECK-LABEL: no_csr_func:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pushq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    callq external@PLT
; CHECK-NEXT:    popq %rax
; CHECK-NEXT:    .cfi_def_cfa_offset 8
; CHECK-NEXT:    retq
  call void @external()
  ret void
}

